package ooo.reindeer.concurrent.netqueue;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import ooo.reindeer.logging.ILogger;
import ooo.reindeer.logging.LogUtil;

import java.util.concurrent.TimeUnit;

public class ConnectListener implements ChannelFutureListener {

    private static final ILogger logger = LogUtil.getLogger(ConnectListener.class);

    Bootstrap connectBootstrap;
    String connectHost;
    int connectPort;
    volatile boolean isActive = false;

    ChannelFuture channelFuture;
    boolean reConnect;

    public ConnectListener(boolean reConnect) {
        this.reConnect = reConnect;
    }

    public ChannelFuture getChannelFuture() {
        if (channelFuture == null || !channelFuture.isSuccess()) throw new RuntimeException("the link is unreachable");
        return channelFuture;

    }

    @Override
    public void operationComplete(final ChannelFuture channelFuture) throws Exception {
        if (channelFuture.isSuccess()) {

            logger.info("connection succeeded [{}]", channelFuture.channel());
        } else {

            channelFuture
                    .channel()
                    .eventLoop()
                    .schedule(new Runnable() {
                        @Override
                        public void run() {
                            watch(connectBootstrap, connectHost, connectPort);
                        }
                    }, 1, TimeUnit.SECONDS);

        }
    }

    public void watch(Bootstrap bootstrap, String host, int port) {

        connectBootstrap = bootstrap;
        connectHost = host;
        connectPort = port;
        channelFuture = bootstrap.connect(host, port);
        if (reConnect) {
            channelFuture.channel().pipeline().addLast(new ChannelInboundHandlerAdapter() {
                @Override
                public void channelInactive(ChannelHandlerContext ctx) throws Exception {
                    isActive = false;
                    watch(connectBootstrap, connectHost, connectPort);
                    super.channelInactive(ctx);
                }

                @Override
                public void channelActive(ChannelHandlerContext ctx) throws Exception {

                    super.channelActive(ctx);
                    isActive = true;
                }
            });
            channelFuture.addListener(this);

            try {
                channelFuture.sync();

                while (!isActive) {
                    TimeUnit.MILLISECONDS.sleep(10);
                }
            } catch (Exception e) {
                logger.debug("connection failure reason", e);
            }
        } else {
            try {
                channelFuture.sync();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}
